package net.imagine.provider.graphicsmagick;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.List;

import net.imagine.core.ImageInfo;
import net.imagine.core.ImageOperations;
import net.imagine.core.ResultState;
import net.imagine.provider.skyline.SkylineImagineUtils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.im4java.core.GMOperation;
import org.im4java.core.GraphicsMagickCmd;
import org.im4java.core.IM4JavaException;
import org.im4java.core.IMOperation;
import org.im4java.core.IdentifyCmd;
import org.im4java.process.ArrayListOutputConsumer;

/**
 * 使用GraphicsMagick作为图片处理工具实现的图片操作类
 * 
 * @author wuqh
 */
public class GMImageOperations implements ImageOperations {
	private static final Log logger = LogFactory.getLog(GMImageOperations.class);
	private String installPath;
	private String ext;

	/**
	 * 设置GraphicsMagick的安装目录
	 * 
	 * @param installPath
	 *            GraphicsMagick的安装目录
	 */
	public void setInstallPath(String installPath) {
		this.installPath = installPath;
	}

	/**
	 * 设置GraphicsMagick的安装目录
	 * 
	 * @param ext
	 *            能使用GraphicsMagick的压缩的格式
	 */
	public void setExt(String ext) {
		this.ext = ext;
	}

	/**
	 * 获取图片信息，包括图片格式，图片宽度，图片高度
	 * 
	 * @param imagePath
	 *            图片路径
	 * 
	 * @return ImageInfo,包括[图片格式，图片宽度，图片高度]
	 * */
	public ImageInfo showImageInfo(String imagePath) {

		IMOperation op = new IMOperation();
		op.addImage();
		IdentifyCmd identifyCmd = new IdentifyCmd(true);
		identifyCmd.setSearchPath(installPath);
		ArrayListOutputConsumer output = new ArrayListOutputConsumer();
		identifyCmd.setOutputConsumer(output);
		try {
			identifyCmd.run(op, imagePath);
		} catch (Exception e) {
			logger.warn("get image info of " + imagePath + " failed", e);
			return null;
		}
		List<String> cmdOutput = output.getOutput();
		String imageInfo = cmdOutput.get(0);
		String validExt[] = ext.split(",");
		int len = validExt.length;
		for (int i = 0; i < len; i++) {
			ImageInfo ret = SkylineImagineUtils.parseImageInfo(imageInfo, validExt[i]);
			if (ret != null) {
				return ret;
			}
		}
		return null;
	}

	/**
	 * 默认图片压缩处理方式，压缩后的图片格式由目标文件后缀控制，不加人工干预；调用者在生成目标图片路径需要带上正确的后缀方可，不特殊处理多帧和透明。
	 * 
	 * @param srcURL
	 *            源图片
	 * @param destURL
	 *            目标图片的路径
	 * @param baseSize
	 *            压缩后的最大长/宽
	 * @see #compressImage(String, String, int)
	 * @return 图片处理结果
	 * 
	 */
	private ResultState scaleImage(String srcURL, String destURL, int baseSize) throws IOException,
			InterruptedException, IM4JavaException {
		GraphicsMagickCmd gmCmd = new GraphicsMagickCmd("convert");
		gmCmd.setSearchPath(installPath);
		GMOperation op = new GMOperation();
		op.addImage();
		// op.addRawArgs("-resize", baseSize + "x" + baseSize + ">");
		op.addRawArgs("-scale", baseSize + "x" + baseSize + ">");
		// op.addRawArgs("-sample", baseSize + "x" + baseSize + ">");
		// op.addRawArgs("-quality", "100");
		op.addImage();
		gmCmd.run(op, srcURL, destURL);
		return ResultState.SUCCESS;
	}

	@Override
	public ResultState resizeImage(String srcURL, String destURL, int baseSize) {
		try {
			return scaleImage(srcURL, destURL, baseSize);
		} catch (Exception e) {
			logger.warn("Exception occurred when run GM command", e);
		}
		return ResultState.PROCESS_IMAGE_FAILED;
	}

	/**
	 * 压缩图片，很低效，效率低于先把InputStream写成文件，再把图片文件缩小
	 * 
	 * @param srcImage
	 *            源图片
	 * @param destURL
	 *            目标图片的路径
	 * @param baseSize
	 *            压缩后的最大长/宽
	 * 
	 * @see #compressImage(String, String, int)
	 * @return 图片处理结果
	 */
	@Deprecated
	@Override
	public ResultState resizeImage(BufferedImage srcImage, String destURL, int baseSize) {
		if (srcImage == null) {
			return ResultState.NOT_IMAGE;
		}
		GraphicsMagickCmd cmd = new GraphicsMagickCmd("convert");
		cmd.setSearchPath(installPath);
		GMOperation op = new GMOperation();
		op.addImage();
		op.resize(baseSize);
		op.addImage();
		try {
			cmd.run(op, srcImage, destURL);
			return ResultState.SUCCESS;
		} catch (IOException e) {
			logger.warn("IOException occurred when run GM command", e);
		} catch (InterruptedException e) {
			logger.debug("catch an InterruptedException in GMImageOperations.resizeImage(BufferedImage, String, int)",
					e);
		} catch (IM4JavaException e) {
			logger.warn("IM4JavaException occurred when run GM command", e);
		}
		return ResultState.PROCESS_IMAGE_FAILED;
	}

	/**
	 * 默认图片压缩处理方式，如果原图有多帧则只压缩第一帧
	 * 
	 * @param srcURL
	 *            源图片
	 * @param destURL
	 *            目标图片的路径
	 * @param baseSize
	 *            压缩后的最大长/宽
	 * @see #compressImage(String, String, int)
	 * @return 图片处理结果
	 * 
	 */
	@Override
	public ResultState resizeFirstFrame(String srcURL, String destURL, int baseSize) {
		if (SkylineImagineUtils.hasMultiFrame(srcURL)) {
			srcURL = srcURL + "[0]";
		}
		return resizeImage(srcURL, destURL, baseSize);
	}

	/**
	 * 剪切图片，从srcImage中以(x,y)为起点切出一张长、宽都为cropSize的图片，并缩放到finalSize大小
	 * 
	 * @param srcURL
	 *            源图片的路径
	 * @param destURL
	 *            目标图片的路径
	 * @param x
	 *            x坐标
	 * @param y
	 *            有坐标
	 * @param cropSize
	 *            需要剪切的大小
	 * @param finalSize
	 *            最终图片的大小
	 * @return 图片处理结果
	 */
	@Override
	public ResultState cropAndResizeImage(String srcURL, String destURL, int x, int y, int cropSize, int finalSize) {
		GraphicsMagickCmd gmCmd = new GraphicsMagickCmd("convert");
		gmCmd.setSearchPath(installPath);
		GMOperation op = new GMOperation();
		op.addImage();
		op.crop(cropSize, cropSize, x, y);
		op.scale(finalSize);
		op.addImage();
		try {
			gmCmd.run(op, srcURL, destURL);
			return ResultState.SUCCESS;
		} catch (Exception e) {
			logger.warn("Exception occurred when run GM command", e);
			return ResultState.PROCESS_IMAGE_FAILED;
		} 
	}

	/**
	 * 剪切图片，从srcImage中以(x,y)为起点切出一张长、宽都为size的图片
	 * 
	 * @param srcURL
	 *            源图片的路径
	 * @param destURL
	 *            目标图片的路径
	 * @param x
	 *            x坐标
	 * @param y
	 *            有坐标
	 * @param size
	 *            需要剪切的大小
	 * 
	 * @return 图片处理结果
	 */
	@Override
	public ResultState cropImage(String srcURL, String destURL, int x, int y, int size) {
		GraphicsMagickCmd gmCmd = new GraphicsMagickCmd("convert");
		gmCmd.setSearchPath(installPath);
		GMOperation op = new GMOperation();
		op.addImage();
		op.crop(size, size, x, y);
		op.addImage();
		try {
			gmCmd.run(op, srcURL, destURL);
			return ResultState.SUCCESS;
		} catch (Exception e) {
			logger.warn("Exception occurred when run GM command", e);
			return ResultState.PROCESS_IMAGE_FAILED;
		} 
	}
	
}
